package org.example;

/**
 * Created by Lenovo
 * DATA:2024/6/22
 **/


import org.entity.Author;

import java.util.Optional;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 *
 * Optional
 * 我们在平常写代码的时候出现做多的就是空指针异常，所以在很多情况下我们需要做各种非空的判断。
 * 例如：
 * Author author=getAuthor();
 * if(author!=null){
 *     System.out.println(author.getName())
 * }
 * 尤其对象中的属性还是一个对象的情况下，这种判断会更多。
 * 而过多的判断语句会让我们的代码显得臃肿不堪。
 * 所以在jdk8 中引入了Optional,养成使用Optional 的习惯后你可以写出更加优雅的代码来避免空指针异常
 * 并且在很多时候，函数式编程相关的API也都用到了Optional ,如果不使用Optional 也会对函数式编程的学习造成影响
 *
 *
 * 使用：
 * Optional 就好像是包装类，可以把我们的具体数据封装Optional对象内部，然后我们去使用Optional 中分装好的方法操作封装进去的数据就可以非常优雅地避免空指针异常
 *
 *
 * 我们一般使用Optional的静态方法ofNullable 来把数据封装成一个Optional 对象，无论传入的参数是否为null都不会出现问题。
 *      Author author=getAuthor();
 *      Optional<Author> author1=Optional.ofNullable(author);
 *你可能会觉得要加一行代码来封装数据比较麻烦，但是如果改造下getAuthor()方法让其返回值就是封装好的Optional的话，我们在使用的时候就会方便很多。
 * 而且在实际开发中我们的数据是从数据库中获取的，而且 Mybatis3.5已经支持Optional了，我们可以直接把dao() 方法的返回值类型定义为Optional类型，
 * Mybatis会自己把数据封装成Optional对象返回。封装过程也不需要我们自己操作。
 *
 *
 * 如果你确定一个对象不是空的则可以使用Optional的静态方法of()来把数据封装成Optional对象。
 *      Author author =new Author();
 *      Optional<Author> author2=Optional.of(author);
 * 但是一定要注意，如果使用of 的时候传入的参数必须不为null。（传入null的时候也会报空指针异常。）
 *
 *
 * 如果一个方法的返回值是Optional类型，而我们经过判断发现某次计算得到的返回值为null，
 * 这个时候就需要把null封装成Optional 对象返回，这时则可以使用Optional的静态方法empty进行封装。
 * Optional.empty()
 *
 *
 *
 * 安全消费值
 *
 * 我们获取到一个Optional 对象后肯定需要对其中的数据进行使用，这时候我们使用ifPresent方法来对消费者中的值进行消费
 * 这个方法会判断其内封装的数据是否为空，不为空时才会执行具体的消费代码，这样使用起来就更加安全了。
 *  Optional<Author> author1 = Optional.ofNullable(author);
 *  author1.ifPresent((a) -> System.out.println(a.getName()));
 *
 *
 *
 *  获取值
 *  如果我们想获取值自己进行处理可以使用get方法获取，但是不推荐，因为但是Optional内部的数据为空的时候会出现异常。
 *
 *
 *
 *
 *  安全获取值
 *
 *  如果我们想安全的获取值，我们不推荐使用get方法，而是使用Optional 提供的以下方法。
 *
 *
 *
 *  orElseGet
 *  获取数据，并且设置数据为空额时候的默认值，如果数据不为空就能获取到该数据，如果为空就根据你传入的参数来创建对象作为默认返回值。
 *      Optional<Author> author1 = Optional.ofNullable(author);
 *      Author author2 = author1.orElseGet(() -> new Author());
 *
 *
 *
 *  orElseThrow
 *  获取数据，如果数据不为空就能获取到该数据，如果为空的话则根据你传入的参数来创建异常抛出。
 *  Optional<Author> author1 = Optional.ofNullable(author);
 *  try{
 *      Author author2 = author1.orElseThrow(() -> new RuntimeException("数据为空"));
 *      System.out.println(author2.getName());
 *  }catch (Exception e){
 *      System.out.println(e.getMessage());
 *  }
 *
 *  过滤
 *
 *  我们可以使用filter方法对数据进行过滤，如果原本是有数据的，但是不符合判断，也会变成一个无数据的Optional对象。
 *  Optional<Author> author1 = Optional.ofNullable(author);
 *  author1.filter((a) -> a.getName().equals("lisi")).ifPresent((a) -> System.out.println(a.getName()));
 *
 * 判断
 *
 * 我们可以使用isPresent方法判断数据是否为空，如果为空就返回false，如果不为空就返回true。但是这种方法不能体现出Optional的好处更推荐使用 ifPresent方法。
 * Optional<Author> author1 = Optional.ofNullable(author);
 * if(author1.isPresent()){
 *      System.out.println(author1.get().getName());
 * }
 *
 *
 * 数据转换
 *
 * Optional 还提供了map 可以让我们对数据进行转换，并且转换得到的数据还是被Optional包装好的，保障了我们的使用安全。
 */
public class OptionalDemo {
    public static void main(String[] args) {
        Author author = null;
        Optional<Author> author1 = Optional.ofNullable(author);
        author1.ifPresent((a) -> System.out.println(a.getName()));


        //orElseGet
        Author author2 = author1.orElseGet(() -> new Author());

        //orElseThrow
        try {
            author1.orElseThrow( () -> new RuntimeException("数据为空"));
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }

        author1.ifPresent((a) -> System.out.println(a.getName()));

        author1.filter(new Predicate<Author>() {
            @Override
            public boolean test(Author author) {
                return false;
            }
        }.and(new Predicate<Author>() {
            @Override
            public boolean test(Author author) {
                return false;
            }
        }));
    }
}
